<?php
/**
 * Copyright (c) 2010, Slawomir Mazur <mazursllawek@gmail.com>
 * 
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions 
 * are met:
 * 
 * o Redistributions of source code must retain the above copyright notice, 
 *   this list of conditions and the following disclaimer.
 * o Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 * o Neither the name of the Softisland nor the names of its contributors
 *   may be used to endorse or promote products derived from this software
 *   without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 
 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
/**
 * Enter description here...
 *
 * @package     default
 * @copyright   Slawomir Mazur (c) 2010 (http://www.zend.com/zce.php?c=ZEND011643)
 * @license     http://www.opensource.org/licenses/bsd-license.php
 * @author      Slawomir Mazur <mazursllawek@gmail.com>
 */

class Gp_View_Helper_Network extends Zend_View_Helper_Abstract
{
	/**
	 * Generate network
	 * 
	 * @param array $parents
	 * @param array $verticies
	 * @param array $orphans
	 * @param array $edges
	 * @param int $libraryId
	 * @param string $geneSymbol gene symbol
	 * 
	 * @return string network file name
	 */
	public function network($parents, $verticies, $orphans, $edges, $libraryId, $geneSymbol)
    {
    	$user = Gp_Auth_UserAuth::getInstance()->getUser();
    	
    	$graph = '';
        $graph .= 
			'<graph label="Cytoscape Web" directed="0" Graphic="1" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:cy="http://www.cytoscape.org" xmlns="http://www.cs.rpi.edu/XGMML">' .
			'    <att name="documentVersion" value="0.1"/>' .
			'    <att type="string" name="backgroundColor" value="#ffffff"/>' . "\n";
        
        foreach ($parents as $parent => $label) {
			$px = $this->getRandFromRange(10, 1000);
			$py = $this->getRandFromRange(10, 1000);
			
			$graph .= 
			'<node id="parent_' . $parent . '" label="' . $label . '">
			<att name="isParent" type="boolean" value="true"/>
			<graphics 
				x="' . $px . '" 
				y="' . $py . '" 
				type="ROUNDRECT" 
				width="0.5" 
				fill="#' . $this->getColor(true) . '" 
				outline="#333333" 
				labelanchor="s" 
				w="1" 
			    h="1" 
				cy:nodeTransparency="0.8"
				cy:nodeLabelFont="Arial-0-11"
			/>
			<att>
				<graph>
			';
			
			// specified for box
			$color = $this->getColor(); 
			$fill = $color['fill'];
			$outline = $color['out'];
			// border			
			$width = (rand(40, 250) / 100.00);
			
			foreach ($verticies as $vertex => $node) {				
				if ($node['parent'] != $parent) {
					continue;
				}
				
				// ball
				$w = $this->getRandFromRange(40, 70);		
				
				$vertexData = explode('_', $vertex);
				$geneSymbol = $vertexData[0];
				$sequence = isset($vertexData[1])? $vertexData[1] : '';
				
				$sequence = ($user)? $sequence : $node['sirnaid'];
				
				 $graph .=
				 '<node id="node_' . $vertex . '" label="' . $sequence . '">
			     <att name="weight" type="real" value="' . $this->getRandFromRange(6, 12) . '"/>
			     <att name="parent" type="string" value="parent_' . $parent . '"/>
			     <att name="gid" type="string" value="' . $node['id'] . '"/>
			     <att name="name" type="string" value="' . $geneSymbol . '"/>
			     <att name="sirna" type="string" value="' . $sequence . '"/>
			     <att name="setName" type="string" value="' . 'setName' . '"/>
			     <graphics 
			    	 x="' . $this->getRandFromRange($px + 10, $px + 190) . '" 
			    	 y="' . $this->getRandFromRange($py + 10, $py + 190) . '" 
				     width="' . $width . '" 
				     type="ELLIPSE" 
				     labelanchor="c" 
				     cy:nodeLabelFont="Arial-0-11" 
				     cy:nodeTransparency="1" 
				     outline="#' . $outline . '" 
				     w="' . $w . '" 
				     h="' . $w . '" 
				     fill="#' . $fill . '"/>
			     </node>
				';
			}
			$graph .= '</graph>
			</att>
			</node>
			';
        }
        
    	/**
		 * Draw nodes without parents
		 * 
		 */
		foreach ($orphans as $vertex => $o) {
			$w = $this->getRandFromRange(30, 50);	
			
			$vertexData = explode('_', $vertex);
			$geneSymbol = $vertexData[0];
			
			$graph .=
				'<node id="node_' . $vertex . '" label="' . $geneSymbol . '">
			     <att name="weight" type="real" value="' . $this->getRandFromRange(6, 12) . '"/>
			     <att name="gid" type="string" value="-"/>
			     <att name="name" type="string" value="' . $geneSymbol . '"/>
			     <att name="sirna" type="string" value="-"/>
			     <att name="setName" type="string" value="' . 'setName' . '"/>
			     <graphics 
			    	 x="' . $this->getRandFromRange(10, 1000) . '" 
			    	 y="' . $this->getRandFromRange(10, 1000) . '" 
				     width="3" 
				     type="ELLIPSE" 
				     labelanchor="c" 
				     cy:nodeLabelFont="Arial-0-11" 
				     cy:nodeTransparency="1" 
				     outline="#1fc9f4" 
				     w="' . $w . '" 
				     h="' . $w . '" 
				     fill="#ff6600"/>
			     </node>
			     ';
		}
        
		$edgeId = 0;
		$netId = 0;
		
		foreach ($edges as $edge) {
			$netId++;
			reset($edge);
			$to  = current($edge);
			$from = key($edge);
			
			if (empty($to) || (isset($edge['type']) && (false !== strpos($edge['type'], 'SKIP')))) {
				continue;
			}
			
			$graph .= 
			'<edge id="e_' . $edgeId++ . '" label="' . $from . ' (16) ' . $to . '" source="node_' . $from . '" directed="true" target="node_' . $to . '">
		     <att name="network" type="string" value="' . $netId . '"/>
		     <att name="weight" type="real" value="' . ($this->getRandFromRange(1, 100) / 100.0) . '"/>
		    
		    ' . $this->_getArrowType($edge) . '
		  	</edge>
		  	';
		}		
        $graph .= '</graph>';
        
        // save
        $file = 'networks/network_library_' . $libraryId . '_' . $geneSymbol . '.xgmml';
        file_put_contents($file, $graph);
        
        return $file;
    }
    
	public function makeSeed()
	{
		list($usec, $sec) = explode(' ', microtime());
		return (float) $sec + ((float) $usec * 100000);
	}
	
	public function getRandFromRange($min, $max)
	{
		mt_srand($this->makeSeed());
		return mt_rand($min, $max);
	}
	
	public function getColor($boxColor = false) {
		if ($boxColor) {
			$number = dechex(rand(9, 14));
			return str_pad('', 6, $number, STR_PAD_RIGHT);
		}
		
		$r = $this->padValue(dechex($rx = rand(0, 128)));
		$g = $this->padValue(dechex($gx = rand(0, 128)));
		$b = $this->padValue(dechex($bx = rand(0, 128)));
			
		$rp = dechex($rx + 127);
		$gp = dechex($gx + 127);
		$bp = dechex($bx + 127);
		
		return array('out' => $r . $g . $b, 'fill' => $rp . $gp . $bp);
	}
	
	public function padValue($value) {
		return str_pad($value, 2, '0', STR_PAD_LEFT);
	}
	
	protected function _getArrowType($edge)
	{
		if (isset($edge['type']) && (false !== strpos($edge['type'], 'BOTH'))) {
			return 
			'<graphics cy:edgeLineType="SOLID" width="2" cy:sourceArrow="3" cy:sourceArrowColor="#000000" cy:targetArrow="3" cy:targetArrowColor="#000000" fill="#000000"/>';
		}
		return 
		'<graphics cy:edgeLineType="SOLID" width="1" cy:sourceArrow="0" cy:sourceArrowColor="#444444" cy:targetArrow="3" cy:targetArrowColor="#444444" fill="#444444"/>';	
	}
	
	public function checkIfNetworkExists($libraryId, $geneSymbol) 
	{
		$file = 'networks/network_library_' . $libraryId . '_' . $geneSymbol . '.xgmml';		
		if (file_exists($file)) {
			return $file;
		}
		return false;
	}
}